package im.oen.boot.common.data;

import im.oen.boot.common.utils.*;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;

/**
 * 顶层的基础对象
 *
 * @author Kevin.Xu
 */
public class Base implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 把此类转换为JSON字符串
     *
     * @return
     */
    public String toJson() {
        return JsonUtil.safeToJson(this);
    }

    /**
     * 把此类转换为XML字符串
     *
     * @return
     */
    public String toXml() {
        return XmlUtil.toXml(this);
    }

    /**
     * 把此类转换为二进制
     *
     * @return
     */
    public byte[] toBytes() {
        return SerializeUtil.obj2Bit(this);
    }

    @Override
    public Base clone() {
        return JsonUtil.safeToObj(this.toJson(), this.getClass());
    }

    public <T> T cloneSelf() {
        return (T) JsonUtil.safeToObj(this.toJson(), this.getClass());
    }


    @Override
    public String toString() {
        return this.toJson();
    }

    /**
     * 从二进制中转换为对象
     *
     * @param bytes 二进制
     * @param clazz 对象类型
     * @param <T>   对象
     * @return 对象
     */
    public static <T extends Base> T from(byte[] bytes, Class<T> clazz) {
        return SerializeUtil.bit2Obj(bytes, clazz);
    }

    /**
     * 从JSON中转换为对象
     *
     * @param json  JSON字符串
     * @param clazz 对象类型
     * @param <T>   对象
     * @return 对象
     */
    public static <T extends Base> T from(String json, Class<T> clazz) {
        return JsonUtil.safeToObj(json, clazz);
    }

    /**
     * 从XML中转换为对象
     *
     * @param clazz 对象类型
     * @param xml   XML字符串
     * @param <T>   对象
     * @return 对象
     */
    public static <T extends Base> T from(Class<T> clazz, String xml) {
        return XmlUtil.toObj(xml, clazz);
    }

    /**
     * 融合，把目标对象中的非空字段赋值到自身中
     *
     * @param target 目标对象
     */
    public void fuse(Base target) {
        if (target == null) {
            return;
        }
        if (this.getClass() != target.getClass()) {
            return;
        }

        List<Field> fields = ReflectUtil.fetchFields(this.getClass());
        for (Field field : fields) {
            Runner.safeRun(() -> {
                Object value = ReflectUtil.fetchValue(target, field);
                if (Checker.isEmptyString(value)) {
                    return;
                }
                ReflectUtil.setFieldValue(this, field, value);
            });
        }
    }
}
